#include <assert.h>
#include <ctype.h>
#include <locale.h>
#include <errno.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <pthread.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include<windows.h>

/*
To call functions which take a variable number of arguments, 
ensure there is a full prototype with the trailing ellipsis in scope: 
void err_exit(const char *format, ...); for example.
*/

/* first arg is the number of following int args to function. */
int count_argument_determine_length_of_va_list(int n, ...)
{
    printf("***** count_argument_determine_length_of_va_list *****\n");
    int sum = 0;
    va_list it; /* hold information about the variadic argument list. */

    va_start(it, n); /* start variadic argument processing */
    while (n--)
        sum += va_arg(it, int); /* get and sum the next variadic argument */
    va_end(it); /* end variadic argument processing */
    printf("sum: %d\n", sum);
    return sum;
}


/* 
function args up until the terminator NAN

Good terminator values:
    integer (supposed to be all positive or non-negative) — 0 or -1
    floating point types — NAN
    pointer types — NULL
    enumerator types — some special value
 */

double terminator_value_determine_end_of_va_list(double x, ...)
{
    printf("***** terminator_value_determine_end_of_va_list *****\n");
    double sum = 0;
    va_list va;

    va_start(va, x);
    for (; !isnan(x); x = va_arg(va, double))
    {
        printf("x: %f\n", x);
        sum += x;
    }
    va_end(va);

    printf("sum: %f\n", sum);
    return sum;
}


int simple_printf(const char *format, ...)
{
    printf("***** simple_printf *****\n");
    va_list ap; /* hold information about the variadic argument list. */
    int printed = 0; /* count of printed characters */
    va_start(ap, format); /* start variadic argument processing */
    while (*format != '\0') /* read format string until string terminator */
    {
        int f = 0;
        if (*format == '%')
        {
            ++format;
            switch(*format)
            {
                case 'c' :
                    f = printf("%d", va_arg(ap, int)); /* print next variadic argument, note type
                    promotion from char to int */
                    break;
                case 'd' :
                    f = printf("%d", va_arg(ap, int)); /* print next variadic argument */
                    break;
                case 'f' :
                    f = printf("%f", va_arg(ap, double)); /* print next variadic argument */
                    break;
                default :
                    f = -1; /* invalid format specifier */
                    break;
            }
        }
        else
        {
            f = printf("%c", *format); /* print any other characters */
        }

        if (f < 0) /* check for errors */
        {
            printed = f;
            break;
        }
        else
        {
            printed += f;
        }
        ++format; /* move on to next character in string */
    }
    va_end(ap); /* end variadic argument processing */
    return printed;
}


void main(void)
{
    count_argument_determine_length_of_va_list(5, 1, 2, 3, 4, 5);

    terminator_value_determine_end_of_va_list(1.0,2.0,3.0,4.0,5.0, NAN);// arguments must be double type, else may checkout error in isnan function.

    int x = 41;
    int y = 0;
    y = simple_printf("There are %d characters in this sentence\n", x);
    simple_printf("%d were printed\n", y);
    system("pause");
}